package com.boot.web.exception.handler;

import com.boot.web.exception.ModuleExceptionHandler;
import com.boot.web.http.HttpModel;
import com.boot.web.http.Status;
import com.boot.web.util.HttpResponseUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.EqualsAndHashCode;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description 为
 * {@link NoHandlerFoundException}
 * {@link ConstraintViolationException}
 * {@link MethodArgumentNotValidException}
 * {@link MethodArgumentTypeMismatchException}
 * 等错误提供错误处理
 * @date 2020/2/16 20:18
 **/
@Deprecated
@Component
@EqualsAndHashCode
public class WebExceptionHandler implements ModuleExceptionHandler {

    @Override
    public boolean support(Exception e) {
        return e instanceof NoHandlerFoundException
                || e instanceof ConstraintViolationException
                || e instanceof MethodArgumentNotValidException
                || e instanceof MethodArgumentTypeMismatchException
                || e instanceof HttpMessageConversionException;
    }

    @Override
    public int order() {
        return 90;
    }

    @Override
    public ResponseEntity<HttpModel<Object>> handle(Exception e) {
        if (e instanceof NoHandlerFoundException) {
            return handleNoHandlerFoundException((NoHandlerFoundException) e);
        } else if (e instanceof ConstraintViolationException) {
            return handleConstraintViolationException((ConstraintViolationException) e);
        } else if (e instanceof MethodArgumentNotValidException) {
            return handleMethodArgumentNotValidException((MethodArgumentNotValidException) e);
        } else if (e instanceof MethodArgumentTypeMismatchException) {
            return handleMethodArgumentTypeMismatchException((MethodArgumentTypeMismatchException) e);
        } else if (e instanceof HttpMessageConversionException) {
            return handleHttpMessageConversionException((HttpMessageConversionException) e);
        } else {
            return HttpResponseUtil.serverError(String.format("%s 不支持 %s", this.getClass().getSimpleName(), e.getClass().getSimpleName()), null);
        }
    }

    private ResponseEntity<HttpModel<Object>> handleNoHandlerFoundException(NoHandlerFoundException e) {
        return HttpResponseUtil.badRequest(String.format("没有找到对应的请求地址：路径 %s ,方法 %s ", e.getRequestURL(), e.getHttpMethod()));
    }

    public ResponseEntity<HttpModel<Object>> handleConstraintViolationException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        StringBuilder builder = new StringBuilder("参数验证失败：");
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            Object invalidValue = constraintViolation.getInvalidValue();
            if (null == invalidValue) {
                builder.append(constraintViolation.getMessage()).append(';');
            } else {
                builder.append("参数值为 ")
                        .append(invalidValue)
                        .append(" , 异常信息 ")
                        .append(constraintViolation.getMessage())
                        .append(';');
            }
        }
        return HttpResponseUtil.badRequest(builder.substring(0, builder.length() - 1));
    }

    public ResponseEntity<HttpModel<Object>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        List<ObjectError> globalErrors = result.getGlobalErrors();
        StringBuilder builder = new StringBuilder("参数验证失败：");
        for (FieldError error : fieldErrors) {
            builder.append("参数名 ")
                    .append(error.getField())
                    .append(", 异常信息 ")
                    .append(error.getDefaultMessage())
                    .append(';');
        }
        for (ObjectError error : globalErrors) {
            builder.append(error.getDefaultMessage()).append(';');
        }
        return HttpResponseUtil.badRequest(builder.substring(0, builder.length() - 1));
    }

    private ResponseEntity<HttpModel<Object>> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        return HttpResponseUtil.badRequest(String.format("方法参数类型错误：参数名 %s, 异常信息 %s ", e.getName(), e.getMessage()));
    }

    private ResponseEntity<HttpModel<Object>> handleHttpMessageConversionException(HttpMessageConversionException e) {
        Throwable rootCause = e.getRootCause();
        if (rootCause == null) {
            return new ResponseEntity<>(
                    HttpModel.<Object>builder().code(Status.NO_REQUEST.getStatus()).msg(Status.NO_REQUEST.getDescription() + " , " + e.getMessage()).build(),
                    HttpStatus.BAD_REQUEST);
        } else if (rootCause instanceof JsonProcessingException) {
            return new ResponseEntity<>(
                    HttpModel.<Object>builder().code(Status.JSON_FAILURE.getStatus()).msg(Status.JSON_FAILURE.getDescription() + " , " + rootCause.getMessage()).build(),
                    HttpStatus.BAD_REQUEST);
        } else {
            return new ResponseEntity<>(
                    HttpModel.<Object>builder().code(Status.NO_REQUEST.getStatus()).msg(Status.NO_REQUEST.getDescription() + " , " + rootCause.getMessage()).build(),
                    HttpStatus.BAD_REQUEST);
        }
    }
}
